package com.wmh.baseservice.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wmh.baseservice.admin.mapper.AdInfoMapper;
import com.wmh.baseservice.admin.pojo.AdInfo;
import com.wmh.baseservice.admin.pojo.AdMenu;
import com.wmh.baseservice.admin.pojo.AdRoleMenu;
import com.wmh.baseservice.admin.pojo.AdRolePermissions;
import com.wmh.baseservice.admin.service.*;
import com.wmh.baseservice.common.config.KeyConfig;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.mybatisplus.methods.CommonServiceImpl;
import com.wmh.baseservice.common.mybatisplus.structure.CustomQueryWrapper;
import com.wmh.baseservice.common.redis.config.RedisConfig;
import com.wmh.baseservice.common.redis.utils.RedisUtil;
import com.wmh.baseservice.common.shiro.config.ShiroConfig;
import com.wmh.baseservice.common.shiro.jwt.JwtTokenUtil;
import com.wmh.baseservice.common.utils.CommUtil;
import com.wmh.baseservice.common.utils.LogUtil;
import com.wmh.baseservice.common.utils.ShiroMd5Util;
import com.wmh.baseservice.common.utils.returnbody.ReturnBody;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mmx generator
 * @since 2021-02-03
 */
@Service
public class AdInfoServiceImpl extends CommonServiceImpl<AdInfoMapper, AdInfo> implements AdInfoService {


    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AdRoleMenuService adRoleMenuService;
    @Resource
    private AdMenuService adMenuService;
    @Resource
    private AdInfoMapper adInfoMapper;
    @Resource
    private AdRolePermissionsService adRolePermissionsService;


    @Override
    public String authority(String account, String password) {
        // 获取管理员用户账号信息
        AdInfo adInfo = adInfoMapper.selectOneForUpdate(new QueryWrapper<AdInfo>().eq(AdInfo.ACCOUNT, account));
        if (null == adInfo) {
            return ReturnBody.error("用户名不存在");
        }
        if (!ShiroMd5Util.decodePwd(adInfo.getPassword(), password + KeyConfig.SHIRO_SALE, adInfo.getSalt())) {
            return ReturnBody.error("用户名或密码错误");
        }
        if (adInfo.getStatus() != 0) {
            return ReturnBody.error("该账号已被冻结, 请联系相关人员");
        }
        // 用户认证
        adInfo.setLoginTime(new Date());
        // 更新登录时间
        if (adInfoMapper.updateById(adInfo) != 1) {
            return ReturnBody.error();
        }
        JSONObject jsonObject = new JSONObject();
        // 秘钥
        String token = "Bearer_" + JwtTokenUtil.generateToken(adInfo.getId(), adInfo.getAccount() + ShiroConfig.SHIRO_ADMIN + ":" + password, 60000);
        jsonObject.put("token", token);
        // 角色菜单
        List<AdMenu> roleMenu = getRoleMenu(adInfo.getRoleId(), adInfo.getId());
        jsonObject.put("menuList", roleMenu);
        jsonObject.put("preList", roleMenu.stream().filter(item -> item.getFlag() == 2).map(AdMenu::getRequestUrl).collect(Collectors.toList()));
        return ReturnBody.success(jsonObject);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String add(AdInfo adInfo) {
        if (adInfoMapper.insert(adInfo) != 1) {
            throw new ServiceException();
        }
        AdRolePermissions adRolePermissions = adRolePermissionsService.getByIdForUpdate(adInfo.getRoleId());
        //设置默认权限
        AdRolePermissions admin = new AdRolePermissions().setRole(adRolePermissions.getRole()).setAdId(adInfo.getId()).setType(1);
        if (!adRolePermissionsService.save(admin)) {
            throw new ServiceException();
        }
        //添加到redis队列中
        String project = RedisConfig.KEY_INFO;
        String key = "role_permissions_" + adInfo.getId() + ShiroConfig.SHIRO_ADMIN + project;
        try {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            Set<String> roles = new HashSet<>();
            roles.add(adRolePermissions.getRole());
            info.setRoles(roles);
            info.setStringPermissions(null);
            redisUtil.set(key, info);
        } catch (Exception e) {
            LogUtil.error("redis角色权限添加错误,key是:" + key + "。原因是:" + e.getMessage());
        }

        return ReturnBody.success();
    }


    @Transactional
    @Override
    public String delete(Long id) {
        //删除账号信息
        if (adInfoMapper.deleteById(id) != 1) {
            throw new ServiceException();
        }
        //删除角色权限表
        List<Long> list = adRolePermissionsService.list(new QueryWrapper<AdRolePermissions>().eq(AdRolePermissions.AD_ID, id)).stream().map(AdRolePermissions::getId).collect(Collectors.toList());
        if (!adRolePermissionsService.removeByIds(list)) {
            throw new ServiceException();
        }
        //删除redis角色权限
        //项目名，区分多项目
        String project = RedisConfig.KEY_INFO;
        String key = "role_permissions_" + id + ShiroConfig.SHIRO_ADMIN + project;
        redisUtil.del(key);
        return ReturnBody.success();
    }

    @Transactional
    @Override
    public void updateInfo(AdInfo adInfo) {
        if (CommUtil.checkNull(adInfo.getRoleId())) {
            String role = adRolePermissionsService.getByIdForUpdate(adInfo.getRoleId()).getRole();
            AdRolePermissions roleRaw = adRolePermissionsService.getOneForUpdate(new QueryWrapper<AdRolePermissions>().eq(AdRolePermissions.AD_ID, adInfo.getId()).eq(AdRolePermissions.TYPE, 1));
            // 判断是否修改角色,比较传过来的role和权限表的role是否一致
            if (!role.equals(roleRaw.getRole())) {
                //更新角色表
                roleRaw.setRole(role);
                //更新redis
                String project = RedisConfig.KEY_INFO;
                String key = "role_permissions_" + adInfo.getId() + ShiroConfig.SHIRO_ADMIN + project;
                SimpleAuthorizationInfo info = (SimpleAuthorizationInfo) redisUtil.get(key);
                Set<String> roleSet = new HashSet<>();
                roleSet.add(roleRaw.getRole());
                info.setRoles(roleSet);
                redisUtil.set(key, info);
                if (!adRolePermissionsService.updateById(roleRaw)) {
                    throw new ServiceException();
                }
            }
        }
        // 更新账号
        if (adInfoMapper.updateById(adInfo) != 1) {
            throw new ServiceException("更新账号失败");
        }
    }




    // 获取该角色拥有权限的菜单
    private List<AdMenu> getRoleMenu(Long roleId, Long id) {
        AdRoleMenu adminRoleMenu = new AdRoleMenu();
        List<AdMenu> list;
        if (id != 1) {
            adminRoleMenu.setRoleId(roleId);
            list = adRoleMenuService.selectRoleMenu(adminRoleMenu);
        } else {
            QueryWrapper<AdMenu> queryWrapper = new CustomQueryWrapper<AdMenu>().orderByDesc(AdMenu.SORT);
            list = adMenuService.list(queryWrapper);
        }

        if (list.size() > 0) {
            redisUtil.hset("roleMenu", roleId.toString(), list);
        } else {
            throw new ServiceException("获取菜单列表失败");
        }
        return list;
    }
}
